﻿/**
 * MOTOR 2 - RAPID FLASH DYNAMICS
 * Copyright (c) 2007-2008, Michael Baczynski
 * Based on the Box2D Engine by Erin Catto, http://www.box2d.org
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * * Neither the name of the polygonal nor the names of its contributors may be
 *   used to endorse or promote products derived from this software without specific
 *   prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package de.polygonal.motor2.collision.pairwise
{
	import de.polygonal.motor2.collision.pairwise.ClipVertex;
	import de.polygonal.motor2.collision.pairwise.FeaturePair;
	import de.polygonal.motor2.collision.shapes.ShapeSkeleton;
	import de.polygonal.motor2.dynamics.contact.Contact;
	import de.polygonal.motor2.dynamics.contact.ContactPoint;
	import de.polygonal.motor2.dynamics.contact.Manifold;
	import de.polygonal.motor2.dynamics.contact.generator.BoxContact;	

	public class CollideBox implements Collider
	{
		private static const _clipVertexIncEdge0:ClipVertex = new ClipVertex();
		private static const _clipVertexIncEdge1:ClipVertex = new ClipVertex();
		
		private static const _clipVertexCp0:ClipVertex = new ClipVertex();
		private static const _clipVertexCp1:ClipVertex = new ClipVertex();
		
		/**
		 * OBB vs. OBB collision detection. This performs a SAT test-intersect
		 * query and computes a contact manifold if the boxes overlap.
		 * 
		 * - the separation distance is computed by applying weightings to
		 *   prefer one axis over another. The factor 1.05 requires a 5%
		 *   increase and 0.01 guards against very small separation magnitudes
		 *   (ERIN - improved coherence).
		 * - the collision normal points from shape 1 to shape 2.
		 * 
		 *        ^ FACE_Y (s1: 1, s2: 3)
		 *        |
		 *        e3
		 *   v2 ------ v3
		 *    |        |
		 * e2 |   CW   | e4  --> FACE_X (s1: 0, s2: 2)
		 *    |        |
		 *   v1 ------ v0
		 *        e1
		 */
		public function collide(manifold:Manifold, s1:ShapeSkeleton, s2:ShapeSkeleton, contact:Contact):void
		{
			var ncollx:Number, ncolly:Number;
			var frontNormalx:Number, frontNormaly:Number;
			var d:Number, sep:Number, minSep:Number, sepAxisId:int;
			var dx:Number = s2.x - s1.x;
			var dy:Number = s2.y - s1.y;
			
			
			var c:BoxContact = BoxContact(contact);
			
			var c11:Number, c21:Number;
			var c12:Number, c22:Number;
			
			//{separating-axis test
			
			//take the sep-axis hint from the last time step
			//as the potential separation axis. if it's overlapping
			//process with all remaining axis.
			
			sepAxisId = c.sepAxisId;
			
			if (false)
			{
			
			
			
			/* check axis 0, 1, 2, 3 */
			if (sepAxisId == 0)
			{
				c11 = s1.r11 * s2.r11 + s1.r21 * s2.r21; if (c11 < 0) c11 = -c11;
				c12 = s1.r11 * s2.r12 + s1.r21 * s2.r22; if (c12 < 0) c12 = -c12;
				
				/* shape1, x-axis (0) */
				
				d = s1.r11 * dx + s1.r21 * dy;
				if (d > 0)
				{
					sep = d - s1.ex - (c11 * s2.ex + c12 * s2.ey);
					if (sep > 0)
					{
						manifold.pointCount = 0;
						return;
					}
					ncollx = s1.r11;
					ncolly = s1.r21;
				}
				else
				{
					sep =-d - s1.ex - (c11 * s2.ex + c12 * s2.ey);
					if (sep > 0)
					{
						manifold.pointCount = 0;
						return;
					}
					ncollx =-s1.r11;
					ncolly =-s1.r21;
				}
				
				minSep = sep;
				
				c22 = s1.r12 * s2.r12 + s1.r22 * s2.r22; if (c22 < 0) c22 = -c22;
				c21 = s1.r12 * s2.r11 + s1.r22 * s2.r21; if (c21 < 0) c21 = -c21;
				
				/* shape1, y-axis (1) */
				
				d = s1.r12 * dx + s1.r22 * dy;
				if (d > 0)
				{
					sep = d - s1.ey - (c21 * s2.ex + c22 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 1;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ey)
					{
						sepAxisId = 1;
						minSep = sep;
						ncollx = s1.r12;
						ncolly = s1.r22;
					}
				}
				else
				{
					sep =-d - s1.ey - (c21 * s2.ex + c22 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 1;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ey)
					{
						sepAxisId = 1;
						minSep = sep;
						ncollx =-s1.r12;
						ncolly =-s1.r22;
					}
				}
				
				/* shape2, x-axis (2) */
				
				d = s2.r11 * dx + s2.r21 * dy;
				if (d > 0)
				{
					sep = d - (c11 * s1.ex + c21 * s1.ey) - s2.ex;
					if (sep > 0)
					{
						c.sepAxisId   = 2;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ex)
					{
						sepAxisId = 2;
						minSep = sep;
						ncollx = s2.r11;
						ncolly = s2.r21;
					}
				}
				else
				{
					sep =-d - (c11 * s1.ex + c21 * s1.ey) - s2.ex;
					if (sep > 0)
					{
						c.sepAxisId   = 2;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ex)
					{
						sepAxisId = 2;
						minSep = sep;
						ncollx =-s2.r11;
						ncolly =-s2.r21;
					}
				}
				
				/* shape2, y-axis (3) */
				
				d = s2.r12 * dx + s2.r22 * dy;
				if (d > 0)
				{
					sep = d - (c12 * s1.ex + c22 * s1.ey) - s2.ey;
					if (sep > 0)
					{
						c.sepAxisId   = 3;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ey)
					{
						sepAxisId = 3;
						minSep = sep;
						ncollx = s2.r12;
						ncolly = s2.r22;
					}
				}
				else
				{
					sep =-d - (c12 * s1.ex + c22 * s1.ey) - s2.ey;
					if (sep > 0)
					{
						c.sepAxisId   = 3;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ey)
					{
						sepAxisId = 3;
						minSep = sep;
						ncollx =-s2.r12;
						ncolly =-s2.r22;
					}
				}
			}
			else
			/* check axis 1, 0, 2, 3 */
			if (sepAxisId == 1)
			{
				c22 = s1.r12 * s2.r12 + s1.r22 * s2.r22; if (c22 < 0) c22 = -c22;
				c21 = s1.r12 * s2.r11 + s1.r22 * s2.r21; if (c21 < 0) c21 = -c21;
				
				/* shape1, y-axis (1) */
				
				d = s1.r12 * dx + s1.r22 * dy;
				if (d > 0)
				{
					sep = d - s1.ey - (c21 * s2.ex + c22 * s2.ey);
					if (sep > 0)
					{
						manifold.pointCount = 0;
						return;
					}
					ncollx = s1.r12;
					ncolly = s1.r22;
				}
				else
				{
					sep =-d - s1.ey - (c21 * s2.ex + c22 * s2.ey);
					if (sep > 0)
					{
						manifold.pointCount = 0;
						return;
					}
					ncollx =-s1.r12;
					ncolly =-s1.r22;
				}
				
				minSep = sep;
				
				c11 = s1.r11 * s2.r11 + s1.r21 * s2.r21; if (c11 < 0) c11 = -c11;
				c12 = s1.r11 * s2.r12 + s1.r21 * s2.r22; if (c12 < 0) c12 = -c12;
				
				/* shape1, x-axis (0) */
				
				d = s1.r11 * dx + s1.r21 * dy;
				if (d > 0)
				{
					sep = d - s1.ex - (c11 * s2.ex + c12 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 0;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ex)
					{
						sepAxisId = 0;
						minSep = sep;
						ncollx = s1.r11;
						ncolly = s1.r21;
					}
				}
				else
				{
					sep =-d - s1.ex - (c11 * s2.ex + c12 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 0;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ex)
					{
						sepAxisId = 0;
						minSep = sep;
						ncollx =-s1.r11;
						ncolly =-s1.r21;
					}
				}
				
				/* shape2, x-axis (2) */
				
				d = s2.r11 * dx + s2.r21 * dy;
				if (d > 0)
				{
					sep = d - (c11 * s1.ex + c21 * s1.ey) - s2.ex;
					if (sep > 0)
					{
						c.sepAxisId   = 2;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ex)
					{
						sepAxisId = 2;
						minSep = sep;
						ncollx = s2.r11;
						ncolly = s2.r21;
					}
				}
				else
				{
					sep =-d - (c11 * s1.ex + c21 * s1.ey) - s2.ex;
					if (sep > 0)
					{
						c.sepAxisId   = 2;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ex)
					{
						sepAxisId = 2;
						minSep = sep;
						ncollx =-s2.r11;
						ncolly =-s2.r21;
					}
				}
				
				/* shape2, y-axis (3) */
				
				d = s2.r12 * dx + s2.r22 * dy;
				if (d > 0)
				{
					sep = d - (c12 * s1.ex + c22 * s1.ey) - s2.ey;
					if (sep > 0)
					{
						c.sepAxisId   = 3;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ey)
					{
						sepAxisId = 3;
						minSep = sep;
						ncollx = s2.r12;
						ncolly = s2.r22;
					}
				}
				else
				{
					sep =-d - (c12 * s1.ex + c22 * s1.ey) - s2.ey;
					if (sep > 0)
					{
						c.sepAxisId   = 3;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ey)
					{
						sepAxisId = 3;
						minSep = sep;
						ncollx =-s2.r12;
						ncolly =-s2.r22;
					}
				}
			}
			else
			/* check axis 2, 0, 1, 3 */
			if (sepAxisId == 2)
			{
				/* shape2, x-axis (2) */
				
				c11 = s1.r11 * s2.r11 + s1.r21 * s2.r21; if (c11 < 0) c11 = -c11;
				c21 = s1.r12 * s2.r11 + s1.r22 * s2.r21; if (c21 < 0) c21 = -c21;
				
				d = s2.r11 * dx + s2.r21 * dy;
				if (d > 0)
				{
					sep = d - (c11 * s1.ex + c21 * s1.ey) - s2.ex;
					if (sep > 0)
					{
						manifold.pointCount = 0;
						return;
					}
					ncollx = s2.r11;
					ncolly = s2.r21;
				}
				else
				{
					sep =-d - (c11 * s1.ex + c21 * s1.ey) - s2.ex;
					if (sep > 0)
					{
						manifold.pointCount = 0;
						return;
					}
					ncollx =-s2.r11;
					ncolly =-s2.r21;
				}
				
				minSep = sep;
				
				c12 = s1.r11 * s2.r12 + s1.r21 * s2.r22; if (c12 < 0) c12 = -c12;
				c22 = s1.r12 * s2.r12 + s1.r22 * s2.r22; if (c22 < 0) c22 = -c22;
				
				/* shape1, x-axis (0) */
				
				d = s1.r11 * dx + s1.r21 * dy;
				if (d > 0)
				{
					sep = d - s1.ex - (c11 * s2.ex + c12 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 0;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ex)
					{
						sepAxisId = 0;
						minSep = sep;
						ncollx = s1.r11;
						ncolly = s1.r21;
					}
				}
				else
				{
					sep =-d - s1.ex - (c11 * s2.ex + c12 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 0;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ex)
					{
						sepAxisId = 0;
						minSep = sep;
						ncollx =-s1.r11;
						ncolly =-s1.r21;
					}
				}
				
				/* shape1, y-axis (1) */
				
				d = s1.r12 * dx + s1.r22 * dy;
				if (d > 0)
				{
					sep = d - s1.ey - (c21 * s2.ex + c22 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 1;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ey)
					{
						sepAxisId = 1;
						minSep = sep;
						ncollx = s1.r12;
						ncolly = s1.r22;
					}
				}
				else
				{
					sep =-d - s1.ey - (c21 * s2.ex + c22 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 1;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ey)
					{
						sepAxisId = 1;
						minSep = sep;
						ncollx =-s1.r12;
						ncolly =-s1.r22;
					}
				}
				
				/* shape2, y-axis (3) */
				
				d = s2.r12 * dx + s2.r22 * dy;
				if (d > 0)
				{
					sep = d - (c12 * s1.ex + c22 * s1.ey) - s2.ey;
					if (sep > 0)
					{
						c.sepAxisId   = 3;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ey)
					{
						sepAxisId = 3;
						minSep = sep;
						ncollx = s2.r12;
						ncolly = s2.r22;
					}
				}
				else
				{
					sep =-d - (c12 * s1.ex + c22 * s1.ey) - s2.ey;
					if (sep > 0)
					{
						c.sepAxisId   = 3;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ey)
					{
						sepAxisId = 3;
						minSep = sep;
						ncollx =-s2.r12;
						ncolly =-s2.r22;
					}
				}
			}
			else
			/* check axis 3, 0, 1, 2 */
			if (sepAxisId == 3)
			{
				c12 = s1.r11 * s2.r12 + s1.r21 * s2.r22; if (c12 < 0) c12 = -c12;
				c22 = s1.r12 * s2.r12 + s1.r22 * s2.r22; if (c22 < 0) c22 = -c22;
				
				/* shape2, y-axis (3) */
				
				d = s2.r12 * dx + s2.r22 * dy;
				if (d > 0)
				{
					sep = d - (c12 * s1.ex + c22 * s1.ey) - s2.ey;
					if (sep > 0)
					{
						manifold.pointCount = 0;
						return;
					}
					ncollx = s2.r12;
					ncolly = s2.r22;
				}
				else
				{
					sep =-d - (c12 * s1.ex + c22 * s1.ey) - s2.ey;
					if (sep > 0)
					{
						manifold.pointCount = 0;
						return;
					}
					ncollx =-s2.r12;
					ncolly =-s2.r22;
				}
				
				minSep = sep;
				
				c11 = s1.r11 * s2.r11 + s1.r21 * s2.r21; if (c11 < 0) c11 = -c11;
				c21 = s1.r12 * s2.r11 + s1.r22 * s2.r21; if (c21 < 0) c21 = -c21;
				
				/* shape1, x-axis (0) */
				
				d = s1.r11 * dx + s1.r21 * dy;
				if (d > 0)
				{
					sep = d - s1.ex - (c11 * s2.ex + c12 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 0;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ex)
					{
						sepAxisId = 0;
						minSep = sep;
						ncollx = s1.r11;
						ncolly = s1.r21;
					}
				}
				else
				{
					sep =-d - s1.ex - (c11 * s2.ex + c12 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 0;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ex)
					{
						sepAxisId = 0;
						minSep = sep;
						ncollx =-s1.r11;
						ncolly =-s1.r21;
					}
				}
				
				/* shape1, y-axis (1) */
				
				d = s1.r12 * dx + s1.r22 * dy;
				if (d > 0)
				{
					sep = d - s1.ey - (c21 * s2.ex + c22 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 1;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ey)
					{
						sepAxisId = 1;
						minSep = sep;
						ncollx = s1.r12;
						ncolly = s1.r22;
					}
				}
				else
				{
					sep =-d - s1.ey - (c21 * s2.ex + c22 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 1;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ey)
					{
						sepAxisId = 1;
						minSep = sep;
						ncollx =-s1.r12;
						ncolly =-s1.r22;
					}
				}
				
				/* shape2, x-axis (2) */
				
				d = s2.r11 * dx + s2.r21 * dy;
				if (d > 0)
				{
					sep = d - (c11 * s1.ex + c21 * s1.ey) - s2.ex;
					if (sep > 0)
					{
						c.sepAxisId   = 2;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ex)
					{
						sepAxisId = 2;
						minSep = sep;
						ncollx = s2.r11;
						ncolly = s2.r21;
					}
				}
				else
				{
					sep =-d - (c11 * s1.ex + c21 * s1.ey) - s2.ex;
					if (sep > 0)
					{
						c.sepAxisId   = 2;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ex)
					{
						sepAxisId = 2;
						minSep = sep;
						ncollx =-s2.r11;
						ncolly =-s2.r21;
					}
				}
			}
			
			}
			else
			{
				c11 = s1.r11 * s2.r11 + s1.r21 * s2.r21; if (c11 < 0) c11 = -c11;
				c12 = s1.r11 * s2.r12 + s1.r21 * s2.r22; if (c12 < 0) c12 = -c12;
				
				/* shape1, x-axis (0) */
				
				d = s1.r11 * dx + s1.r21 * dy;
				if (d > 0)
				{
					sep = d - s1.ex - (c11 * s2.ex + c12 * s2.ey);
					if (sep > 0)
					{
						manifold.pointCount = 0;
						return;
					}
					ncollx = s1.r11;
					ncolly = s1.r21;
				}
				else
				{
					sep =-d - s1.ex - (c11 * s2.ex + c12 * s2.ey);
					if (sep > 0)
					{
						manifold.pointCount = 0;
						return;
					}
					ncollx =-s1.r11;
					ncolly =-s1.r21;
				}
				
				minSep = sep;
				
				c22 = s1.r12 * s2.r12 + s1.r22 * s2.r22; if (c22 < 0) c22 = -c22;
				c21 = s1.r12 * s2.r11 + s1.r22 * s2.r21; if (c21 < 0) c21 = -c21;
				
				/* shape1, y-axis (1) */
				
				d = s1.r12 * dx + s1.r22 * dy;
				if (d > 0)
				{
					sep = d - s1.ey - (c21 * s2.ex + c22 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 1;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ey)
					{
						sepAxisId = 1;
						minSep = sep;
						ncollx = s1.r12;
						ncolly = s1.r22;
					}
				}
				else
				{
					sep =-d - s1.ey - (c21 * s2.ex + c22 * s2.ey);
					if (sep > 0)
					{
						c.sepAxisId   = 1;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s1.ey)
					{
						sepAxisId = 1;
						minSep = sep;
						ncollx =-s1.r12;
						ncolly =-s1.r22;
					}
				}
				
				/* shape2, x-axis (2) */
				
				d = s2.r11 * dx + s2.r21 * dy;
				if (d > 0)
				{
					sep = d - (c11 * s1.ex + c21 * s1.ey) - s2.ex;
					if (sep > 0)
					{
						c.sepAxisId   = 2;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ex)
					{
						sepAxisId = 2;
						minSep = sep;
						ncollx = s2.r11;
						ncolly = s2.r21;
					}
				}
				else
				{
					sep =-d - (c11 * s1.ex + c21 * s1.ey) - s2.ex;
					if (sep > 0)
					{
						c.sepAxisId   = 2;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ex)
					{
						sepAxisId = 2;
						minSep = sep;
						ncollx =-s2.r11;
						ncolly =-s2.r21;
					}
				}
				
				/* shape2, y-axis (3) */
				
				d = s2.r12 * dx + s2.r22 * dy;
				if (d > 0)
				{
					sep = d - (c12 * s1.ex + c22 * s1.ey) - s2.ey;
					if (sep > 0)
					{
						c.sepAxisId   = 3;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ey)
					{
						sepAxisId = 3;
						minSep = sep;
						ncollx = s2.r12;
						ncolly = s2.r22;
					}
				}
				else
				{
					sep =-d - (c12 * s1.ex + c22 * s1.ey) - s2.ey;
					if (sep > 0)
					{
						c.sepAxisId   = 3;
						manifold.pointCount = 0;
						return;
					}
					if (sep > .95 * minSep + .01 * s2.ey)
					{
						sepAxisId = 3;
						minSep = sep;
						ncollx =-s2.r12;
						ncolly =-s2.r22;
					}
				}
			}
			
			
			
			
			//}
			
			//compute clipping planes (reference face side planes)
			var incShape:ShapeSkeleton;
			var front:Number, side:Number, negSide:Number, posSide:Number;
			var sideNormalx:Number, sideNormaly:Number;
			var negEdge:int, posEdge:int;
			var flipFeatures:Boolean = false;
			
			if (sepAxisId == 0)
			{
				incShape = s2;
				
				frontNormalx = ncollx;
				frontNormaly = ncolly;
				
				front = s1.x * frontNormalx + s1.y * frontNormaly + s1.ex;
				side  = s1.x * (sideNormalx = s1.r12) + s1.y * (sideNormaly = s1.r22);
				
				negSide = -side + s1.ey; negEdge = 1;
				posSide =  side + s1.ey; posEdge = 3;
			}
			else
			if (sepAxisId == 1)
			{
				incShape = s2;
				
				frontNormalx = ncollx;
				frontNormaly = ncolly;
				
				front = s1.x * frontNormalx + s1.y * frontNormaly + s1.ey;
				side  = s1.x * (sideNormalx = s1.r11) + s1.y * (sideNormaly = s1.r21);
				
				negSide = -side + s1.ex; negEdge = 2;
				posSide =  side + s1.ex; posEdge = 4;
			}
			else
			if (sepAxisId == 2)
			{
				incShape = s1;
				flipFeatures = true;
				
				frontNormalx =-ncollx;
				frontNormaly =-ncolly;
				
				front = s2.x * frontNormalx + s2.y * frontNormaly + s2.ex;
				side  = s2.x * (sideNormalx = s2.r12) + s2.y * (sideNormaly = s2.r22);
				
				negSide = -side + s2.ey; negEdge = 1;
				posSide =  side + s2.ey; posEdge = 3;
			}
			else
			if (sepAxisId == 3)
			{
				incShape = s1;
				flipFeatures = true;
				
				frontNormalx =-ncollx;
				frontNormaly =-ncolly;
				
				front = s2.x * frontNormalx + s2.y * frontNormaly + s2.ey;
				side  = s2.x * (sideNormalx = s2.r11) + s2.y * (sideNormaly = s2.r21);
				
				negSide = -side + s2.ex; negEdge = 2;
				posSide =  side + s2.ex; posEdge = 4;
			}
			
			//find incident edge
			var incEdgeCv0:ClipVertex = _clipVertexIncEdge0;
			var incEdgeCv1:ClipVertex = _clipVertexIncEdge1;
			
			//convert front normal to incident shape's local space
			//and flip sign rotT * (-N)
			var nx:Number = -incShape.r11 * frontNormalx - incShape.r21 * frontNormaly;
			var ny:Number = -incShape.r12 * frontNormalx - incShape.r22 * frontNormaly;
			
			if ((nx < 0 ? -nx : nx) > (ny < 0 ? -ny : ny))
			{
				if (nx > 0)
				{
					incEdgeCv0.x = incShape.ex;
					incEdgeCv0.y =-incShape.ey;
					incEdgeCv0.fp.inEdge2  = 1;
					incEdgeCv0.fp.outEdge2 = 4;
					
					incEdgeCv1.x = incShape.ex;
					incEdgeCv1.y = incShape.ey;
					incEdgeCv1.fp.inEdge2  = 4;
					incEdgeCv1.fp.outEdge2 = 3;
				}
				else
				{
					incEdgeCv0.x =-incShape.ex;
					incEdgeCv0.y = incShape.ey;
					incEdgeCv0.fp.inEdge2  = 3;
					incEdgeCv0.fp.outEdge2 = 2;
					
					incEdgeCv1.x =-incShape.ex;
					incEdgeCv1.y =-incShape.ey;
					incEdgeCv1.fp.inEdge2  = 2;
					incEdgeCv1.fp.outEdge2 = 1;
				}
			}
			else
			{
				if (ny > 0)
				{
					incEdgeCv0.x = incShape.ex;
					incEdgeCv0.y = incShape.ey;
					incEdgeCv0.fp.inEdge2  = 4;
					incEdgeCv0.fp.outEdge2 = 3;
					
					incEdgeCv1.x =-incShape.ex;
					incEdgeCv1.y = incShape.ey;
					incEdgeCv1.fp.inEdge2  = 3;
					incEdgeCv1.fp.outEdge2 = 2;
				}
				else
				{
					incEdgeCv0.x =-incShape.ex;
					incEdgeCv0.y =-incShape.ey;
					incEdgeCv0.fp.inEdge2  = 2;
					incEdgeCv0.fp.outEdge2 = 1;
					
					incEdgeCv1.x = incShape.ex;
					incEdgeCv1.y =-incShape.ey;
					incEdgeCv1.fp.inEdge2  = 1;
					incEdgeCv1.fp.outEdge2 = 4;
				}
			}
			
			//transform clipping vertices back to world space
			var xt:Number = incEdgeCv0.x;
			var yt:Number = incEdgeCv0.y;
			incEdgeCv0.x = incShape.x + incShape.r11 * xt + incShape.r12 * yt;
			incEdgeCv0.y = incShape.y + incShape.r21 * xt + incShape.r22 * yt;
			
			xt = incEdgeCv1.x;
			yt = incEdgeCv1.y;
			incEdgeCv1.x = incShape.x + incShape.r11 * xt + incShape.r12 * yt;
			incEdgeCv1.y = incShape.y + incShape.r21 * xt + incShape.r22 * yt;
			
			//compute contact points
			var cvOut0:ClipVertex = _clipVertexCp0;
			var cvOut1:ClipVertex = _clipVertexCp1;
			
			var dist0:Number, dist1:Number, interp:Number;
			
			//<--| clip to negative side
			dist0 = incEdgeCv0.x * -sideNormalx + incEdgeCv0.y * -sideNormaly - negSide;
			dist1 = incEdgeCv1.x * -sideNormalx + incEdgeCv1.y * -sideNormaly - negSide;
			
			//on different sides of the clipping plane
			if (dist0 * dist1 < 0)
			{
				//find intersection edge-plane
				interp = dist0 / (dist0 - dist1);
				
				//behind the plane
				cvOut0 = dist0 < 0 ? incEdgeCv0 : incEdgeCv1;
				
				//on the plane
				cvOut1.x = incEdgeCv0.x + interp * (incEdgeCv1.x - incEdgeCv0.x);
				cvOut1.y = incEdgeCv0.y + interp * (incEdgeCv1.y - incEdgeCv0.y);
				
				if (dist0 > 0)
				{
					cvOut1.fp = incEdgeCv0.fp;
					cvOut1.fp.inEdge1 = negEdge;
					cvOut1.fp.inEdge2 = FeaturePair.NO_EDGE;
				}
				else
				{
					cvOut1.fp = incEdgeCv1.fp;
					cvOut1.fp.outEdge1 = negEdge;
					cvOut1.fp.outEdge2 = FeaturePair.NO_EDGE;
				}
			}
			else
			{
				//both points in front of the plane
				if (dist0 > 0 && dist1 > 0)
				{
					manifold.pointCount = 0;
					return;
				}
				
				//both points behind the plane
				if (dist0 < dist1)
				{
					cvOut0 = incEdgeCv0;
					cvOut1 = incEdgeCv1;
				}
				else
				{
					cvOut1 = incEdgeCv0;
					cvOut0 = incEdgeCv1;
				}
			}
			
			//clip to positive side |-->
			dist0 = cvOut0.x * sideNormalx + cvOut0.y * sideNormaly - posSide;
			dist1 = cvOut1.x * sideNormalx + cvOut1.y * sideNormaly - posSide;
			
			if (dist0 * dist1 < 0)
			{
				interp = dist0 / (dist0 - dist1);
				
				cvOut0.x = cvOut0.x + interp * (cvOut1.x - cvOut0.x);
				cvOut0.y = cvOut0.y + interp * (cvOut1.y - cvOut0.y);
				
				if (dist0 > 0)
				{
					cvOut0.fp = cvOut0.fp;
					cvOut0.fp.inEdge1 = posEdge;
					cvOut0.fp.inEdge2 = FeaturePair.NO_EDGE;
				}
				else
				{
					cvOut0.fp = cvOut1.fp;
					cvOut0.fp.outEdge1 = posEdge;
					cvOut0.fp.outEdge2 = FeaturePair.NO_EDGE;
				}
			}
			else
			{
				if (dist0 > 0)
				{
					manifold.pointCount = 0;
					return;
				}
			}
			//}
			
			//{output contact manifold
			
			//cvOut0 and cvOut1 are potential clipping points.
			//ERIN: due to roundoff, it is possible that clipping removes all points.
			var cp:ContactPoint;
			sep = frontNormalx * cvOut0.x + frontNormaly * cvOut0.y - front;
			if (sep <= 0)
			{
				manifold.pointCount = 1;
				manifold.nx = ncollx;
				manifold.ny = ncolly;
				
				cp = manifold.c0;
				cp.sep = sep;
				cp.x   = cvOut0.x;
				cp.y   = cvOut0.y;
				
				//TODO optimize inline feature copy and flip
				cp.feature.paste(cvOut0.fp);
				if (flipFeatures) cp.feature.flip();
				
				sep = frontNormalx * cvOut1.x + frontNormaly * cvOut1.y - front;
				if (sep <= 0)
				{
					manifold.pointCount = 2;
					
					cp = manifold.c1;
					cp.sep = sep;
					cp.x   = cvOut1.x;
					cp.y   = cvOut1.y;
					
					cp.feature.paste(cvOut1.fp);
					if (flipFeatures) cp.feature.flip();
				}
			}
			else
			{
				sep = frontNormalx * cvOut1.x + frontNormaly * cvOut1.y - front;
				if (sep <= 0)
				{
					manifold.pointCount = 1;
					manifold.nx = ncollx;
					manifold.ny = ncolly;
					
					cp = manifold.c0;
					cp.sep = sep;
					cp.x   = cvOut1.x;
					cp.y   = cvOut1.y;
					
					cp.feature.paste(cvOut1.fp);
					if (flipFeatures) cp.feature.flip();
					manifold.pointCount = 1;
				}
			}
			//}
		}
	}
}